package org.sfnelson.sk.client;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.sfnelson.sk.client.data.Loot;
import org.sfnelson.sk.client.data.User;
import org.sfnelson.sk.client.event.Created;
import org.sfnelson.sk.client.event.Joined;
import org.sfnelson.sk.client.event.Left;
import org.sfnelson.sk.client.event.ReceivedLoot;
import org.sfnelson.sk.client.rpc.AdminService;
import org.sfnelson.sk.client.rpc.AdminServiceAsync;
import org.sfnelson.sk.client.rpc.Event;
import org.sfnelson.sk.client.rpc.EventListener;
import org.sfnelson.sk.client.rpc.EventManager;
import org.sfnelson.sk.client.rpc.EventService;
import org.sfnelson.sk.client.rpc.EventServiceAsync;
import org.sfnelson.sk.client.rpc.LoginInfo;
import org.sfnelson.sk.client.rpc.LoginService;
import org.sfnelson.sk.client.rpc.LoginServiceAsync;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.Location;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Suicide_Kings extends EventManager implements EntryPoint {

	private final EventServiceAsync eventService = GWT.create(EventService.class);
	private final AdminServiceAsync adminService = GWT.create(AdminService.class);

	private LoginInfo loginInfo = null;

	public Suicide_Kings() {
		raid = new RaidTracker();
		addListener(raid);
	}

	public void onModuleLoad() {
		// Check login status using login service.
		LoginServiceAsync loginService = GWT.create(LoginService.class);
		loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() {
			public void onFailure(Throwable error) {
			}

			public void onSuccess(LoginInfo result) {
				loginInfo = result;
				if(loginInfo.isLoggedIn()) {
					loadSuicideKings();
				} else {
					Location.replace(loginInfo.getLoginUrl());
				}
			}
		});
	}

	private void loadSuicideKings() {

		final FormPanel head = new FormPanel();

		final TextBox toon = new TextBox();
		toon.setStyleName("toonInput");

		final Button submit = new Button("Add");
		submit.setStyleName("add");
		submit.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				head.submit();
			}
		});

		final Button edit = new Button("Edit");
		edit.setStyleName("edit");
		edit.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				RootPanel.get().addStyleName("editing");
			}
		});

		final Button done = new Button("Done");
		done.setStyleName("done");
		done.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				RootPanel.get().removeStyleName("editing");
			}
		});

		Panel header = new FlowPanel();
		header.add(toon);
		Panel buttons = new FlowPanel();
		buttons.setStyleName("buttons");
		buttons.add(submit);
		buttons.add(edit);
		buttons.add(done);
		header.add(buttons);

		head.add(header);
		head.setStyleName("header");
		head.addSubmitHandler(new SubmitHandler() {

			public void onSubmit(SubmitEvent event) {
				String name = toon.getText();
				toon.setText("");
				if (name.length() > 0) {
					eventService.created(lastEvent, name, eventHandler);
				}
			}
		});

		AddUser adder = new AddUser() {
			public void addUser(User user) {
				eventService.joined(lastEvent, user, eventHandler);
			}
		};

		RemoveUser remover = new RemoveUser() {
			public void removeUser(User user) {
				eventService.left(lastEvent, user, eventHandler);
			}
		};

		final FormPanel foot = new FormPanel();
		final TextBox user = new TextBox();
		final TextBox loot = new TextBox();
		final Button giveLoot = new Button("Assign");
		giveLoot.setStyleName("");
		Panel footer = new FlowPanel();
		footer.add(user);
		footer.add(loot);
		footer.add(giveLoot);
		foot.add(footer);
		foot.setStyleName("footer");
		giveLoot.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				foot.submit();
			}
		});
		foot.addSubmitHandler(new SubmitHandler() {
			public void onSubmit(SubmitEvent event) {
				if (loot.getText().length() > 0 && user.getText().length() > 0) {
					String l = loot.getText();
					String u = user.getText();
					loot.setText("");
					user.setText("");
					try {
						User uu = raid.get(u);
						int lid = Integer.parseInt(l);
						Loot lootObject = new Loot(lid);
						System.out.println("sending " + lootObject);
						eventService.receivedLoot(lastEvent, uu, lootObject, "suicide", eventHandler);
					} catch (NumberFormatException ex) {}
				}
			}
		});

		RootPanel.get().add(new LadderPanel(head, foot, adder, remover));
		RootPanel.get().add(new LogPanel());

		Button clear = new Button("Clear");
		clear.setStyleName("clear");
		clear.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {
				adminService.clearAll(new AsyncCallback<Void>() {
					public void onFailure(Throwable caught) {
						System.out.println("network problem clearing data");
					}

					public void onSuccess(Void result) {
						System.out.println("cleared all data");
						Window.Location.reload();
					}
				});
			}
		});
		RootPanel.get().add(clear);

		Timer timer = new Timer() {
			@Override
			public void run() {
				listen();
			}
		};
		timer.scheduleRepeating(10000);
		timer.run();
	}

	private Date lastEvent;
	public void listen() {
		eventService.listen(lastEvent, eventHandler);
	}

	private final AsyncCallback<List<Event>> eventHandler = new AsyncCallback<List<Event>>() {

		public void onFailure(Throwable caught) {
			System.err.println("error occured while processing event");
			caught.printStackTrace();
		}

		public void onSuccess(List<Event> result) {
			if (result == null) return;

			for (Event event: result) {
				org.sfnelson.sk.client.event.Event e = event.asEvent();
				if (lastEvent == null || e.date.after(lastEvent)) {
					lastEvent = e.date;
					event(e);
				}
			}
		}
	};

	private final RaidTracker raid;

	private class RaidTracker implements EventListener {

		private final Map<String, User> raid = new HashMap<String, User>();

		public void onCreated(Created event) {
			// Nothing to do.
		}

		public void onJoined(Joined event) {
			raid.put(event.user.getName(), event.user);
		}

		public void onLeft(Left event) {
			raid.remove(event.user.getName());
		}

		public void onReceivedLoot(ReceivedLoot event) {
			// Nothing to do.
		}

		public User get(String name) {
			return raid.get(name);
		}

	}
}
